<?php
/**
 * Created by PhpStorm.
 * User: caoyangmin
 * Date: 16/11/10
 * Time: 下午9:14
 */

namespace Once\Utils;

use Laravel\Lumen\Application;
use Once\Api;
use Once\Exceptions\AnnotationSyntaxExceptions;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;

class Validator
{
    /**
     * Validation constructor.
     * @param Application $app
     */
    public function __construct(Application $app)
    {
        $this->app = $app;
    }

    /**
     * @param string $name
     * @param string|null $type
     * @param string|null $expr
     * @param boolean $isOptional
     */
    function addRule($name, $type, $expr){
        //1. 针对基本类型, 使用Lumen的校验方法
        //先将$type和$expr拼成Lumen的校验表达式
        if(TypeHint::isScalarType($type) || $type==null){
            if(!$expr){
                if($type){
                    $this->rules[$name] = $type;
                }
            }else{
                $this->rules[$name] = "$type|$expr";
            }
        }else{
            //TODO * 支持对象数组
            //2. 针对对象, 不支持Lumen的校验方法
            !$expr or Verify::fail(new AnnotationSyntaxExceptions("$name $expr, validation not work with object"));
            $this->objectRules[$name] = $type;
        }
    }
    /**
     * 校验参数
     * @param array $data
     * @param string[] $rules
     */
    function validate(array $data){

        // 先处理基本类型
        $vld = $this->app->make('validator');
        $vld = $vld->make($data, $this->rules);

        !$vld->fails() or Verify::fail(new BadRequestHttpException($vld->errors()->first()));
        $data = $vld->getData();
        // 再处理对象类型
        foreach ($this->objectRules as $k => $v){
            if(TypeHint::isArray($v)){ //如果是对象数组
                is_array($data[$k]) or Verify::fail(new \InvalidArgumentException("param $k required $v"));
                foreach ($data[$k] as &$i){
                    $i = Api::getInstance()->makeEntity($this->app, TypeHint::getArrayType($v), $i);
                }
            }else{
                $data[$k] = Api::getInstance()->makeEntity($this->app, $v, $data[$k]);
            }
        }

        return $data;
    }

    /**
     * @var string[]
     */
    private  $rules=[];

    /**
     * @var string[]
     */
    private  $objectRules=[];

    /**
     * @var Application
     */
    private $app;
}